﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace OnlineLogCommon
{
    internal class ConnectInfo
    {
        public Socket ServerSocket { get; set; }
    }

    public class SocketTcpServer
    {
        public event Action<Socket> AcceptCompleted;
        public event Action<Packet, object> ReceiveCompleted;

        List<SocketAsyncEventArgs> _SocketAsyncEventArgs = new List<SocketAsyncEventArgs>();
        SocketAsyncEventArgs Pop()
        {
            foreach (var item in _SocketAsyncEventArgs)
            {
                if (item.AcceptSocket == null)
                {
                    return item;
                }
            }
            return null;
        }
        public void Listen(string host, int port)
        {
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Bind(new IPEndPoint(IPAddress.Parse(host), port));
            socket.Listen(10);

            for (int i = 0; i < 10; i++)
            {
                var socketAsyncEventArgs = new SocketAsyncEventArgs();
                socketAsyncEventArgs.Completed += async_completed;
                _SocketAsyncEventArgs.Add(socketAsyncEventArgs);
            }
            BeginAccept(socket);
        }

        private void BeginAccept(Socket socket)
        {
            var args = Pop();
            if (args == null)
            {
                args = new SocketAsyncEventArgs();
                args.Completed += async_completed;
                _SocketAsyncEventArgs.Add(args);
            }
            if (!socket.AcceptAsync(args))
                Accept_Completed(socket, args);
        }

        private void async_completed(object sender, SocketAsyncEventArgs e)
        {
            if (e.LastOperation == SocketAsyncOperation.Receive)
            {
                Receive_Completed(sender, e);
            }
            else if (e.LastOperation == SocketAsyncOperation.Accept)
            {
                Accept_Completed(sender, e);
            }
        }

        void Accept_Completed(object sender, SocketAsyncEventArgs e)
        {
            var sendbuffers = new byte[1024];
            e.SetBuffer(sendbuffers, 0, 1024);
            e.UserToken = new { };
            e.AcceptSocket.ReceiveAsync(e);
            if (AcceptCompleted != null)
                AcceptCompleted(e.AcceptSocket);

            Socket server = sender as Socket;
            BeginAccept(server);

        }
        void Receive_Completed(object sender, SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success && e.BytesTransferred > 0)
            {
                byte[] data = new byte[e.BytesTransferred];
                Array.Copy(e.Buffer, e.Offset, data, 0, data.Length);
                var packet = new Packet();
                packet.Version = 1;
                packet.PacketType = PacketType.String;
                packet.Length = data.Length;
                var dataStr = Encoding.UTF8.GetString(data);
                if (ReceiveCompleted != null)
                    ReceiveCompleted(packet, dataStr);

                System.Diagnostics.Debugger.Log(1, "", dataStr + Environment.NewLine);
                if (!e.AcceptSocket.ReceiveAsync(e))
                    Receive_Completed(null, e);
            }
            else
            {
                e.AcceptSocket = null;
            }
        }
    }
}
